home *** CD-ROM | disk | FTP | other *** search
/ Celestin Apprentice 4 / Apprentice-Release4.iso / Source Code / Add-Ons / MPW / MPW noweb 2.7 / src / c / mnt.nw (.txt) < prev    next >
Encoding:
LaTeX Document  |  1995-05-30  |  5.4 KB  |  159 lines  |  [TEXT/MPS ]

  1. % Copyright 1991 by Norman Ramsey.  All rights reserved.
  2. % See file COPYRIGHT for more information.
  3. \subsection{Expanding multiple files from a single source}
  4. This main program is used to make the monolithic {\tt noweb}
  5. script efficient.
  6. Tips of the hat to Ross Williams and Preston Briggs.
  7. <<*>>=
  8. #include <stdio.h>
  9. #include <string.h>
  10. #include <stdlib.h>
  11. #include <assert.h>
  12. #include <ctype.h>
  13. #include "modules.h"
  14. #include "modtrees.h"
  15. #include "notangle.h"
  16. #include "errors.h"
  17. #include "columns.h"
  18. #include "strsave.h"
  19. <<local prototypes>>
  20. #define Clocformat "#line %L \"%F\"%N"
  21. static char *locformat = Clocformat;
  22. main(int argc, char **argv) {
  23.     int i;
  24.     tabsize = 0;  /* default for nt is not to use tabs */
  25.     <<read standard input into tree>>
  26.     for (i=1; i<argc; i++) 
  27.       switch (*argv[i]) {
  28.         case '-': <<handle option in [[argv[i]]]>>                 break;
  29.         default:  emitfile(argv[i]);                               break;
  30.       }
  31.     exit(errorlevel);
  32.     return errorlevel;        /* slay warning */
  33. <<read standard input into tree>>=
  34. read_defs(stdin);
  35. apply_each_module(remove_final_newline);
  36. <<write out all conforming roots>>=
  37. apply_each_module(add_uses_to_usecounts);
  38. apply_each_module(emit_if_unused_and_conforming);
  39. <<local prototypes>>=
  40. void add_uses_to_usecounts(Module mp);
  41. void emit_if_unused_and_conforming(Module mp);
  42. <<*>>=
  43. void add_uses_to_usecounts(Module mp) {
  44.     Module used;
  45.     struct modpart *p;
  46.     for (p=mp->head; p!=NULL; p=p->next)
  47.     if (p->ptype == MODULE) {
  48.         used = lookup(p->contents);
  49.         if (used != NULL)
  50.         used->usecount++;
  51. @ %def add_uses_to_usecounts
  52. A conforming output chunk name has no spaces and no metacharacters.
  53. Names with spaces are silently ignored, but names that are otherwise
  54. conforming but that contain metacharacters cause complaints.
  55. <<*>>=
  56. void emit_if_unused_and_conforming(Module mp) {
  57.     char *index;
  58.     if (mp->usecount == 0 && strpbrk(mp->name, " \n\t\v\r\f") == NULL)
  59.         if (index = strpbrk(mp->name, "[](){}!$&<>*?;|^`'\\\""),
  60.             index == NULL || index[0] == '*' && index[1] == 0)
  61.           emitfile(mp->name);
  62.         else 
  63.         errormsg(Error, "@<<%s@>> cannot be an output chunk; "
  64.                             "it contains a metacharacter", mp->name);
  65. @ %def emit_if_unused_and_conforming
  66. <<local prototypes>>=
  67. static void emitfile(char *modname);
  68. <<*>>=
  69. static void emitfile(char *modname) { 
  70.   Module root = lookup(modname);
  71.   char *tempname = tempnam(".", 0);
  72.   FILE *fp;
  73.   char *lfmt, *filename;
  74.   <<set [[lfmt]] and [[filename]] from [[modname]]>>
  75.   <<complain and [[return]] if [[root == NULL]]>>
  76.   fp = fopen(tempname, "w");
  77.   if (fp == NULL) errormsg(Fatal, "Can't open temporary file %s", tempname);
  78.   <<expand [[root]] onto [[fp]] and close the file>>
  79.   <<if file [[filename]] is as file [[tempname]], remove [[tempname]] and [[return]]>>
  80.   remove(filename);
  81.   if (rename(tempname, filename) != 0) { /* different file systems? (may have to copy) */
  82.     FILE *fp = fopen(filename, "w");
  83.     if (fp == NULL) {remove(tempname); <<complain about [[filename]] and [[return]]>>}
  84.     <<expand [[root]] onto [[fp]] and close the file>>
  85.     remove(tempname);
  86. @ %def emitfile
  87. <<set [[lfmt]] and [[filename]] from [[modname]]>>=
  88. { int n = strlen(modname) - 1;
  89.   if (n >= 0 && modname[n] == '*') {
  90.     lfmt = locformat;
  91.     filename = strsave(modname);
  92.     filename[n] = 0;
  93.   } else {
  94.     lfmt = "";
  95.     filename = modname;
  96. <<expand [[root]] onto [[fp]] and close the file>>=
  97. resetloc();
  98. (void) expand(root, 0, 0, 0, lfmt, fp);
  99. putc('\n', fp);
  100. fclose(fp);
  101. <<if file [[filename]] is as file [[tempname]], remove [[tempname]] and [[return]]>>=
  102. { FILE *dest, *tmp;
  103.   dest = fopen(filename, "r");
  104.   if (dest != NULL) {
  105.     int x, y;
  106.     tmp = fopen(tempname, "r");
  107.     assert(tmp);
  108.     do { 
  109.       x = getc(tmp);
  110.       y = getc(dest);
  111.     } while (x == y && x != EOF);
  112.     fclose(tmp);
  113.     fclose(dest);
  114.     if (x == y) {
  115.       remove(tempname);
  116.       return;
  117.     }
  118. <<complain about [[filename]] and [[return]]>>=
  119. errormsg(Error, "Can't open output file %s", filename);
  120. return;
  121. <<complain and [[return]] if [[root == NULL]]>>=
  122. if (root == NULL) {
  123.   errormsg(Error, "Chunk @<<%s@>> is undefined", filename);
  124.   return;
  125. <<handle option in [[argv[i]]]>>=
  126.     switch (*++argv[i]) {
  127.         case 'a':
  128.             if (strcmp(argv[i], "all"))
  129.                 errormsg(Warning, "Ignoring unknown option -%s", argv[i]);
  130.             else {<<write out all conforming roots>>}
  131.             break;
  132.     case 't': /* set tab size or turn off */
  133.         if (isdigit(argv[i][1]))
  134.             tabsize = atoi(argv[i]+1);
  135.         else if (argv[i][1]==0)
  136.             tabsize = 0;         /* no tabs */
  137.         else 
  138.             errormsg(Error, "%s: ill-formed option %s\n", argv[0], argv[i]);
  139.         break;        
  140.         case 'L': /* have a #line number format */
  141.             locformat = argv[i] + 1;
  142.             if (!*locformat) locformat = Clocformat;
  143.             break;
  144.         default:
  145.             errormsg(Warning, "Ignoring unknown option -%s", argv[i]);
  146.      }
  147. \subsubsection{Temporary files}
  148. Some operating systems provide a [[tempnam]] call that makes it possible to 
  149. create a temporary file in the current directory.  This makes [[mnt]] more 
  150. efficient by making [[rename]] efficient.  If your operating system
  151. provides [[tempnam]], define [[TEMPNAM]] for compilation.
  152. <<local prototypes>>=
  153. #ifdef TEMPNAM
  154. extern char *tempnam (const char *dir, const char *pfx);    /* temp file in dir */
  155. #else
  156. #define tempnam(DIR,PFX) (strsave(tmpnam(NULL)))
  157. #endif
  158. @ %def tempnam
  159.